package com.drei.wolke.shiro;

import java.util.HashMap;
import java.util.Map;

import javax.annotation.Resource;
import javax.servlet.Filter;

import org.apache.shiro.mgt.RememberMeManager;
import org.apache.shiro.realm.Realm;
import org.apache.shiro.session.mgt.SessionManager;
import org.apache.shiro.session.mgt.eis.JavaUuidSessionIdGenerator;
import org.apache.shiro.session.mgt.eis.SessionDAO;
import org.apache.shiro.session.mgt.eis.SessionIdGenerator;
import org.apache.shiro.session.mgt.quartz.QuartzSessionValidationScheduler;
import org.apache.shiro.spring.LifecycleBeanPostProcessor;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.filter.authc.FormAuthenticationFilter;
import org.apache.shiro.web.filter.authc.LogoutFilter;
import org.apache.shiro.web.mgt.CookieRememberMeManager;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.apache.shiro.web.servlet.SimpleCookie;
import org.apache.shiro.web.session.mgt.DefaultWebSessionManager;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.DependsOn;

import com.drei.wolke.shiro.cache.RedisCacheManager;
import com.drei.wolke.shiro.realm.CustomRealm;
import com.drei.wolke.shiro.session.RedisSessionDAO;

import at.pollux.thymeleaf.shiro.dialect.ShiroDialect;

@Configuration
public class ShiroConfig {

	// 1、获取配置的Realm，之所以没使用注解配置，是因为此处需要考虑到加密处理
	//设置realms 认证授权,域，领域 相当于数据源，通过realm存储认证，授权信息
	@Resource
	private CustomRealm customRealm ;
	
	
	
 
	// 2配置sessionid生成器，不依赖web
	@Bean
	public SessionIdGenerator getSessionIdGenerator() { // 3
		return new JavaUuidSessionIdGenerator();
	}

	// 3 session的持久化配置shiro会话缓存技术，通过SessionDAO管理session数据
	@Bean
	public SessionDAO getSessionDAO(SessionIdGenerator sessionIdGenerator) {
		RedisSessionDAO sessionDAO = new RedisSessionDAO(); // 使用Redis进行Session管理
		sessionDAO.setActiveSessionsCacheName("shiro-activeSessionCache");
		sessionDAO.setSessionIdGenerator(sessionIdGenerator);
		return sessionDAO;
	}

	//4 session管理器， web应用中一般是web容器对session管理，shiro也提供一套session的管理方式
	@Bean
	public DefaultWebSessionManager getSessionManager(SessionDAO sessionDAO,
			QuartzSessionValidationScheduler sessionValidationScheduler) { // 6
		DefaultWebSessionManager sessionManager = new DefaultWebSessionManager();
		sessionManager.setGlobalSessionTimeout(1000000);
		sessionManager.setDeleteInvalidSessions(true);
		sessionManager.setSessionValidationScheduler(sessionValidationScheduler);
		sessionManager.setSessionValidationSchedulerEnabled(true);
		sessionManager.setSessionDAO(sessionDAO);
		SimpleCookie sessionIdCookie = new SimpleCookie("neusoft-session-id");
		sessionIdCookie.setHttpOnly(true);
		sessionIdCookie.setMaxAge(-1);
		sessionManager.setSessionIdCookie(sessionIdCookie);
		sessionManager.setSessionIdCookieEnabled(true);
		return sessionManager;
	}

	// 5 记住我处理
	@Bean
	public RememberMeManager getRememberManager() {
		CookieRememberMeManager rememberMeManager = new CookieRememberMeManager();
		SimpleCookie cookie = new SimpleCookie("neusoft-RememberMe");
		cookie.setHttpOnly(true);
		cookie.setMaxAge(3600);
		rememberMeManager.setCookie(cookie);
		return rememberMeManager;
	}

	@Bean(name = "lifecycleBeanPostProcessor")
	public LifecycleBeanPostProcessor getLifecycleBeanPostProcessor() {
		return new LifecycleBeanPostProcessor();
	}

	@Bean
	@DependsOn("lifecycleBeanPostProcessor")
	public DefaultAdvisorAutoProxyCreator getDefaultAdvisorAutoProxyCreator() {
		DefaultAdvisorAutoProxyCreator daap = new DefaultAdvisorAutoProxyCreator();
		daap.setProxyTargetClass(true);
		return daap;
	}

	@Bean
	public QuartzSessionValidationScheduler getQuartzSessionValidationScheduler() {
		QuartzSessionValidationScheduler sessionValidationScheduler = new QuartzSessionValidationScheduler();
		sessionValidationScheduler.setSessionValidationInterval(100000);
		return sessionValidationScheduler;
	}

	@Bean
	public AuthorizationAttributeSourceAdvisor getAuthorizationAttributeSourceAdvisor(
			DefaultWebSecurityManager securityManager) {
		AuthorizationAttributeSourceAdvisor aasa = new AuthorizationAttributeSourceAdvisor();
		aasa.setSecurityManager(securityManager);
		return aasa;
	}

	// shiro的核心处理器，reaml需要加入到sessionManager
	// subject是主体
	// 安全管理器，主体通过认证和授权都是通过sessionManager
	@Bean
	public DefaultWebSecurityManager getSecurityManager(Realm memberRealm, RedisCacheManager cacheManager,
			SessionManager sessionManager, RememberMeManager rememberMeManager) {// 7
		DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
		securityManager.setRealm(memberRealm);
		securityManager.setCacheManager(cacheManager);
		securityManager.setSessionManager(sessionManager);
		securityManager.setRememberMeManager(rememberMeManager);
		return securityManager;
	}

	// 认证过滤器在ShiroFilterFactoryBean中使用
	public FormAuthenticationFilter getLoginFilter() {
		FormAuthenticationFilter filter = new FormAuthenticationFilter();
		filter.setUsernameParam("username");
		filter.setPasswordParam("password");
		filter.setRememberMeParam("rememberMe");
		filter.setLoginUrl("/loginPage"); // 登录提交页面
		filter.setFailureKeyAttribute("error");
		return filter;
	}

	// 登出过滤器 在ShiroFilterFactoryBean中使用
	public LogoutFilter getLogoutFilter() {
		LogoutFilter logoutFilter = new LogoutFilter();
		logoutFilter.setRedirectUrl("/"); // 首页路径，登录注销后回到的页面
		return logoutFilter;
	}

	// 不在需要配置web.xml中的shiorFilter来指定ShiroFilterFactoryBean
	@Bean
	public ShiroFilterFactoryBean getShiroFilterFactoryBean(DefaultWebSecurityManager securityManager) {
		ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
		// shiro核心处理器 必须设置 SecurityManager
		shiroFilterFactoryBean.setSecurityManager(securityManager);
		// 设置登录页路径
		shiroFilterFactoryBean.setLoginUrl("/loginPage");
		// 设置跳转成功页
		shiroFilterFactoryBean.setSuccessUrl("/pages/hello");
		// 授权错误页
		shiroFilterFactoryBean.setUnauthorizedUrl("/pages/unauthUrl");
		Map<String, Filter> filters = new HashMap<String, Filter>();
		// 设置登录处理的过滤器
		filters.put("authc", this.getLoginFilter());
		// 设置登出的过滤器
		filters.put("logout", this.getLogoutFilter());
		// 加载到处理器中
		shiroFilterFactoryBean.setFilters(filters);
		Map<String, String> filterChainDefinitionMap = new HashMap<String, String>();
		// anon为匿名访问
		// authc 必须通过认证才能访问
		filterChainDefinitionMap.put("/logout", "logout");
		filterChainDefinitionMap.put("/loginPage", "authc"); // 定义内置登录处理
		filterChainDefinitionMap.put("/pages/back/**", "authc");
		filterChainDefinitionMap.put("/*", "anon");
		shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
		return shiroFilterFactoryBean;
	}

	// 必须配置此操作才可以使用thymeleaf-extras-shiro开发包
	@Bean
	public ShiroDialect getShiroDialect() {
		return new ShiroDialect();
	}
}
